package com.greendizer.api.resource.seller;

import java.util.HashMap;

import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;

import com.greendizer.api.client.AbstractClient;
import com.greendizer.api.resource.AbstractInvoice;
import com.greendizer.api.resource.ResourceId;


/**
 * Represents an invoice from the seller perspective.
 */
public class Invoice extends AbstractInvoice {

  /**
   * Creates a new invoice with the API client, its parent email URI and its id.
   * @param client API client.
   * @param emailURI Parent email URI.
   * @param id Email id.
   */
  public Invoice(AbstractClient<?, ?, ?> client, String emailURI, ResourceId id) {
    super(client, emailURI, id);
  }

  /**
   * Creates a new invoice with the API client and its parent email URI.
   * @param client API client.
   * @param emailURI Parent email URI.
   */
  public Invoice(AbstractClient<?, ?, ?> client, String emailURI) {
    this(client, emailURI, null);
  }

  /**
   * Deserialises data received from the server and fills the invoice properties.
   * @param map Raw parsed data from server to be fully qualified.
   * @throws ParseException If an error occurred while parsing the data.
   */
  @Override
  protected void deserialize(JSONObject map) throws ParseException {
    super.deserialize(map);
    setProperty("buyer", new Recipient(map.get("buyer").toString()));
    Object shipping = map.get("shipping");
    if (shipping != null) {
      setProperty("shipping", new Shipping(shipping.toString()));
    }
  }

  /**
   * Returns the buyer info holder.
   * @return Buyer info holder.
   */
  public Recipient getBuyer() {
    return (Recipient) getProperty("buyer");
  }

  /**
   * Returns the shipping info holder.
   * @return Shipping info holder.
   */
  public Shipping getShipping() {
    return (Shipping) getProperty("shipping");
  }

  /**
   * Holder class representing a recipient with his name, email and postal address.
   * @author Youssef El Bied
   */
  public class Recipient {

    private HashMap<String, Object> properties;

    /**
     * Deserialiazes a new recipient instance from the given raw JSON string.
     * @param content Raw JSON string to be deserialiazed.
     * @throws ParseException If an error occurred while parsing the data.
     */
    private Recipient(String content) throws ParseException {
      JSONObject map = (JSONObject) parser.parse(content);
      properties = new HashMap<String, Object>();
      properties.put("uri", parseString(map, "uri"));
      properties.put("name", parseString(map, "name"));
      properties.put("email", parseString(map, "email"));
      properties.put("address", new Address(parseString(map, "address")));
    }

    /**
     * Returns the URI of the recipient.
     * @return The URI of the recipient.
     */
    public String getURI() {
      return (String) properties.get("uri");
    }

    /**
     * Returns the name of the recipient.
     * @return The name of the recipient.
     */
    public String getName() {
      return (String) properties.get("name");
    }

    /**
     * Returns the email of the recipient.
     * @return The email of the recipient.
     */
    public String getEmail() {
      return (String) properties.get("email");
    }

    /**
     * Returns the address of the recipient.
     * @return The address of the recipient.
     */
    public Address getAddress() {
      return (Address) properties.get("address");
    }

    /**
     * Returns a string representation of the recipient.
     */
    public String toString() {
      return properties.toString();
    }

    /**
     * Holder class representing a postal address with its street address, zip code, city, state and country.
     * @author Youssef El Bied
     */
    public class Address {

      private HashMap<String, Object> properties;

      /**
       * Deserialiazes a new address instance from the given raw JSON string.
       * @param content Raw JSON string to be deserialiazed.
       * @throws ParseException If an error occurred while parsing the data.
       */
      private Address(String content)  throws ParseException {
        JSONObject map = (JSONObject) parser.parse(content);
        properties = new HashMap<String, Object>();
        properties.put("streetAddress", parseString(map, "streetAddress"));
        properties.put("zipcode", parseString(map, "zipcode"));
        properties.put("city", parseString(map, "city"));
        properties.put("state", parseString(map, "state"));
        properties.put("country", parseString(map, "country"));
      }

      /**
       * Returns the address street address.
       * @return Address street address.
       */
      public String getStreetAddress() {
        return (String) properties.get("streetAddress");
      }

      /**
       * Returns the address zip code.
       * @return Address zip code.
       */
      public String getZipcode() {
        return (String) properties.get("zipcode");
      }

      /**
       * Returns the address city.
       * @return Address city.
       */
      public String getCity() {
        return (String) properties.get("city");
      }

      /**
       * Returns the address state.
       * @return Address state.
       */
      public String getState() {
        return (String) properties.get("state");
      }

      /**
       * Returns the address country.
       * @return Address country.
       */
      public String getCountry() {
        return (String) properties.get("country");
      }

      /**
       * Returns a string representation of the address.
       */
      public String toString() {
        return properties.toString();
      }
    }
  }

  /**
   * Holder class representing a shipping info.
   * @author Youssef El Bied
   */
  public class Shipping {

    private HashMap<String, Object> properties;

    /**
     * Deserialiazes a new shipping info instance from the given raw JSON string.
     * @param content Raw JSON string to be deserialiazed.
     * @throws ParseException If an error occurred while parsing the data.
     */
    private Shipping(String content) throws ParseException {
      JSONObject map = (JSONObject) parser.parse(content);
      properties = new HashMap<String, Object>();
      properties.put("recipient", new Recipient(parseString(map, "recipient")));
    }

    /**
     * Returns the shipping info recipient.
     * @return Shipping info recipient.
     */
    public Recipient getRecipient() {
      return (Recipient) properties.get("recipient");
    }

    /**
     * Returns a string representation of the shipping info.
     */
    public String toString() {
      return properties.toString();
    }
  }
}
